"use client"; import { useQuery } from "@tanstack/react-query"; import { useParams } from "next/navigation"; import { format } from "date-fns"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@nextsparkjs/core/components/ui/card"; import { Button } from "@nextsparkjs/core/components/ui/button"; import { Badge } from "@nextsparkjs/core/components/ui/badge"; import { Avatar, AvatarFallback } from "@nextsparkjs/core/components/ui/avatar"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@nextsparkjs/core/components/ui/table"; import { ArrowLeft, Users, User, Calendar, Loader2, AlertTriangle, RefreshCw, Crown, Shield, Eye, CreditCard, CheckCircle, Clock, XCircle, AlertCircle, Receipt, ExternalLink, TrendingUp, } from "lucide-react"; import Link from "next/link"; import { getTemplateOrDefaultClient } from "@nextsparkjs/registries/template-registry.client"; interface TeamOwner { id: string; name: string; email: string; } interface TeamMember { id: string; userId: string; name: string; email: string; role: "owner" | "admin" | "member" | "viewer"; joinedAt: string; } interface Team { id: string; name: string; owner: TeamOwner; memberCount: number; createdAt: string; updatedAt: string; } interface SubscriptionPlan { id: string; slug: string; name: string; type: string; priceMonthly: number | null; priceFormatted: string; } interface Subscription { id: string; plan: SubscriptionPlan; status: string; currentPeriodStart: string; currentPeriodEnd: string; trialEndsAt: string | null; canceledAt: string | null; cancelAtPeriodEnd: boolean; externalSubscriptionId: string | null; externalCustomerId: string | null; paymentProvider: string | null; providerName: string | null; providerDashboardUrl: string | null; createdAt: string; } interface BillingEvent { id: string; type: string; status: string; amount: number; amountFormatted: string; currency: string; invoiceUrl: string | null; receiptUrl: string | null; createdAt: string; } interface UsageData { [key: string]: { current: number; periodKey: string; }; } interface TeamDetailData { team: Team; members: TeamMember[]; subscription: Subscription | null; billingHistory: BillingEvent[]; usage: UsageData; metadata: { requestedBy: string; requestedAt: string; source: string; }; } const roleIcons = { owner: Crown, admin: Shield, member: User, viewer: Eye, }; const roleColors = { owner: "destructive", admin: "default", member: "secondary", viewer: "outline", } as const; /** * Team Detail Page * * Displays detailed information about a specific team for superadmins (read-only). */ function TeamDetailPage() { const params = useParams()!; const teamId = params.teamId as string; // Fetch team data from API const { data: teamData, isLoading, error, refetch } = useQuery({ queryKey: ["superadmin-team", teamId], queryFn: async () => { const response = await fetch(`/api/superadmin/teams/${teamId}`); if (!response.ok) { if (response.status === 404) { throw new Error("Team not found"); } throw new Error("Failed to fetch team data"); } return response.json(); }, retry: 2, staleTime: 30000, }); // Get team initials for avatar const getTeamInitials = (name: string) => { const words = name.split(" "); if (words.length >= 2) { return `${words[0][0]}${words[1][0]}`.toUpperCase(); } return name.slice(0, 2).toUpperCase(); }; // Loading state if (isLoading) { return (

Team Details

Loading team data...

); } // Error state if (error) { return (

Team Details

Error loading data

Error Loading Team {error instanceof Error ? error.message : "Failed to load team data"}
); } const team = teamData?.team; const members = teamData?.members || []; return (
{/* Header */}

Team Details

View team information and members (read-only)

{/* Team Info Card */}
{team?.name ? getTeamInitials(team.name) : "??"}
{team?.name}
ID: {team?.id}
{/* Owner */}

Owner

{team?.owner.name?.[0]?.toUpperCase() || "?"}
{team?.owner.name}
{team?.owner.email}
{/* Members */}

Members

{team?.memberCount || 0} {team?.memberCount === 1 ? "member" : "members"}
{/* Created */}

Created

{team?.createdAt ? format(new Date(team.createdAt), "MMMM dd, yyyy") : "Unknown"}
{/* Members Table */} Team Members ({members.length}) All members of this team and their roles. {members.length === 0 ? (

No members

This team has no members yet.

) : (
Member Email Role Joined {members.map((member) => { const RoleIcon = roleIcons[member.role] || User; return (
{member.name?.[0]?.toUpperCase() || "?"}
{member.name}
{member.email} {member.role.charAt(0).toUpperCase() + member.role.slice(1)}
{member.joinedAt ? format(new Date(member.joinedAt), "MMM dd, yyyy") : "Unknown"}
); })}
)}
{/* Subscription Section */} {teamData?.subscription ? ( Subscription Current subscription status and billing information.
{/* Plan */}

Current Plan

{teamData.subscription.plan.name} {teamData.subscription.plan.priceFormatted}
{/* Status */}

Status

{teamData.subscription.status === 'active' && } {teamData.subscription.status === 'trialing' && } {teamData.subscription.status === 'past_due' && } {teamData.subscription.status === 'canceled' && } {teamData.subscription.status.charAt(0).toUpperCase() + teamData.subscription.status.slice(1).replace('_', ' ')} {teamData.subscription.cancelAtPeriodEnd && (

Cancels at period end

)}
{/* Current Period */}

Current Period

{format(new Date(teamData.subscription.currentPeriodStart), "MMM dd")} - {format(new Date(teamData.subscription.currentPeriodEnd), "MMM dd, yyyy")}
{/* Trial / External Links */}
{teamData.subscription.trialEndsAt && ( <>

Trial Ends

{format(new Date(teamData.subscription.trialEndsAt), "MMM dd, yyyy")}
)} {teamData.subscription.providerDashboardUrl && ( <>

{teamData.subscription.providerName || 'Payment Provider'}

View in {teamData.subscription.providerName || 'Dashboard'} )}
{/* Subscription Metadata */}
Subscription ID: {teamData.subscription.id} {teamData.subscription.externalCustomerId && ( Customer ID: {teamData.subscription.externalCustomerId} )}
) : ( Subscription

No Subscription

This team does not have an active subscription.

)} {/* Billing History */} {teamData?.billingHistory && teamData.billingHistory.length > 0 && ( Billing History Recent payment events and invoices.
Date Type Status Amount Actions {teamData.billingHistory.map((event) => (
{format(new Date(event.createdAt), "MMM dd, yyyy")}
{event.type.replace('_', ' ')} {event.status === 'succeeded' && } {event.status === 'pending' && } {event.status === 'failed' && } {event.status.charAt(0).toUpperCase() + event.status.slice(1)} {event.amountFormatted}
{event.invoiceUrl && ( Invoice )} {event.receiptUrl && ( Receipt )}
))}
)} {/* Usage Summary */} {teamData?.usage && Object.keys(teamData.usage).length > 0 && ( Current Usage Resource usage for the current billing period.
{Object.entries(teamData.usage).map(([limitSlug, usage]) => (
{limitSlug.replace(/_/g, ' ')}
{usage.current.toLocaleString()}
Period: {usage.periodKey}
))}
)} {/* Metadata Footer */} {teamData?.metadata && (

Last updated:{" "} {new Date(teamData.metadata.requestedAt).toLocaleString()}

Requested by: {teamData.metadata.requestedBy}

Source: {teamData.metadata.source}

)}
); } export default getTemplateOrDefaultClient( "app/superadmin/teams/[teamId]/page.tsx", TeamDetailPage );